//
//$Id: fa.h 679 2011-03-12 16:50:06Z andrew.tsyganov $
#pragma once

//#include "stdafx.h"
#include "types.h"
#include "sets.h"
#include "adjacent.h"
#include "re.h"
#include "re2fa.h"

const std::string kFAXmlNode              = "fa";
const std::string kFAXmlNameAttr          = "name";
const std::string kFAXmlSymbolsNumAttr    = "symbols_num";
const std::string kFAXmlStatesNumAttr     = "states_num";

const std::string kFAXmlEpsilonNode       = "epsilon";

const std::string kFAXmlSymbolsNode       = "symbols";
const std::string kFAXmlSymbolNode        = "symbol";

const std::string kFAXmlStatesNode        = "states";
const std::string kFAXmlStateNode         = "state";

const std::string kFAXmlIDAttr            = "id";

const std::string kFAXmlInitialNode       = "initial";
const std::string kFAXmlFinalNode         = "final";

const std::string kFAXmlDeltaNode         = "delta";
const std::string kFAXmlTransitionNode    = "transition";
const std::string kFAXmlSrcAttr           = "src";
const std::string kFAXmlSymAttr           = "sym";
const std::string kFAXmlDstAttr           = "dst";

const std::string kFADefaultEpsilonName   = "epsilon"; 

class FA
{
private:
    std::string name_;
    u_t symbols_num_;
    u_t states_num_;

	Label epsilon_;
	std::vector<Label> symbols_;
    std::vector<Label> states_;

    Subset initial_, final_;

	std::vector<Adjacent> delta_;

	u_t transitions_num_;
    
	void find_Simple_Loops_DSF(std::vector<Simple_Loop>& vsl, Path& p, BitSet& visited) const;
public:
	// constructors
	FA();
	FA(std::string const& name, u_t const symbols_num, u_t const states_num = 0, std::string const& epsilon = kFADefaultEpsilonName); 
	FA(std::string const& file);
	FA(FA const& fa);
	FA(RE const& re);

	// init and clear
	void init(std::string const& name, u_t const symbols_num, u_t const states_num = 0, std::string const& epsilon = kFADefaultEpsilonName);
	void clear();

	// name routines
	inline std::string get_Name() const { return name_; }
	inline void set_Name(std::string name) { name_ = name; }

	// epsilon routines
	inline std::string get_Epsilon() const { return epsilon_; }
	inline void set_Epsilon(std::string const& epsilon) { epsilon_ = epsilon; }

	// symbols routines
	inline u_t get_Symbols_Num() const { return symbols_num_; }
	u_t get_Symbol_ID(Label const& sym) const;
	inline std::vector<Label> const& get_Symbols() const { return symbols_; }
	
	void set_Symbols(std::vector<Label> const& vl);
	inline void reset_Symbols() { symbols_.clear(); }
	
	std::string symbol_To_String(u_t const id, std::string const& pfx = "", Labels_Type const lt = TXT) const;

	// states routines
	inline u_t get_States_Num() const { return states_num_; }
	u_t get_State_ID(Label const& state) const;
	inline std::vector<Label> const& get_States() const { return states_; }
	
	void set_States(std::vector<Label> const& vs);
	inline void reset_States() { states_.clear(); }
	
	std::string state_To_String(u_t const id, std::string const& pfx = "", Labels_Type const lt = TXT) const;
	std::string states_To_String(Subset const& s, std::string const& pfx = "", Brackets_Type const bt = BRACES, Labels_Type const lt = TXT) const;
	
	u_t add_State();
	u_t add_States(u_t n);
	u_t add_State(Label const& state);
	void swap_States(u_t const id1, u_t const id2);
	void remove_State(u_t const id);

	// initial routines
	inline bool is_Initial(u_t const id) const { return initial_.contains(id); }
	
	inline u_t get_Initial_Num() const { return initial_.size(); }
	inline Subset const& get_Initial() const { return initial_; }
	
	void set_Initial(u_t const id, bool flag = true);
	void set_Initial(Subset const& s, bool flag = true);
	void reset_Initial() { initial_.remove(); }

	// final routines
	inline bool is_Final(u_t const id) const { return final_.contains(id); }
	
	inline u_t get_Final_Num() const { return final_.size(); }
	inline Subset const& get_Final() const { return final_; }
	
	void set_Final(u_t const id, bool flag = true);
	void set_Final(Subset const& s, bool flag = true);
	void reset_Final() { final_.remove(); }

	// transitions routines
	inline std::vector<Adjacent> const& get_Delta() const { return delta_; };

    u_t add_Transition(u_t const src_id, u_t const sym_id, u_t const dst_id);
    u_t add_Transitions(u_t const src_id, u_t const sym_id, Subset const& dst_s);
	
	u_t remove_Transition(u_t const src_id, u_t const sym_id, u_t const dst_id);
	u_t remove_Transition_By_Num(u_t const num);
	
	u_t get_Transitions_Num() const { return transitions_num_; }
	u_t calc_Out_Transitions_Num(u_t const src_id) const;
	u_t calc_Out_Transitions_Num(u_t const src_id, u_t sym_id) const;
	u_t calc_In_Transitions_Num(u_t const dst_id) const;
	u_t calc_In_Transitions_Num(u_t const dst_id, u_t const sym_id) const;
	
	std::string transition_To_String(u_t const src_id, u_t const sym_id, u_t const dst_id, Labels_Prefix lp = kDefaultLabelsPfx) const;

	void print_Transitions_TXT(std::ostream& os, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void print_Transitions_TXT(std::ostream& os, u_t const src_id, Labels_Prefix lp = kDefaultLabelsPfx) const;

	// miscellaneous routines
	void print_Path_TXT(std::ostream& os, Path const& p, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void find_Simple_Loops(std::vector<Simple_Loop>& vsl) const;

	Subset move(Subset const& s, u_t const sym_id) const;
	Subset epsilon_Closure(Subset const& s) const;

	bool is_Acceptable(std::vector<Label> const& vs) const;
	bool is_Acceptable(std::vector<u_t> const& vu) const;
	
	bool is_Deterministic() const;
	bool is_Epsilon() const;
	bool is_Dense() const;

	void make_Dense(Label const& state = "");

	// printing routines
	std::string to_GAP() const;

	void print_GV(std::ostream& os, Labels_Prefix lp = kDefaultLabelsPfx) const;
    void print_LaTeX(std::ostream& os, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void print_LaTeX(std::ostream& os, FA const& fa, std::vector<Subset> const& vs_fa, Labels_Prefix lp_fa = kDefaultLabelsPfx, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void print_TXT(std::ostream& os, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void print_TXT(std::ostream& os, FA const& fa, std::vector<Subset> const& vs_fa, Labels_Prefix lp_fa = kDefaultLabelsPfx, Labels_Prefix lp = kDefaultLabelsPfx) const;
	void print_XML(std::ostream& os, int flag = 0) const;

	// saving and loading routines
    bool save(std::string const& dir, std::string const& name, std::string const& format) const;
    bool save_GAP(std::string const& file) const;
    bool save_GV(std::string const& file) const;
    bool save_LaTeX(std::string const& file) const;
    bool save_TXT(std::string const& file) const;
    bool save_XML(std::string const& file) const;

    bool load_XML(std::string const& file);

	// serialization and deserialization routines
	unsigned char* serialize(unsigned& len) const; 
    void deserialize(unsigned char const* buf);    
};

void MakeCanonicalLoop(Loop& l);

//EOF!
